﻿using CPPEI.Coolzon.Common;
using CPPEI.Coolzon.DataTask;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Threading;
using Visifire.Charts;

namespace CPPEI.Coolzon.UI
{
    /// <summary>
    /// 数据组件
    /// </summary>
    public abstract partial class DataPart : ControlPart, IDataPart
    {
        /// <summary>
        /// 是否在加载数据中
        /// </summary>
        private bool _isLoadingData = false;
        /// <summary>
        /// 数据开始加载的时间
        /// </summary>
        private long _beginDataLoadTicks = 0;
        #region Private variables

        public string DataSourceName { get; set; }
        public string DataSetName { get; set; }
        public ServiceProxy.DataServiceRef.DataParameter[] DataParameters { get; set; }

        /// <summary>
        /// 原始数据，过滤前的
        /// </summary>
        public ServiceProxy.DataServiceRef.DataResult OriginalDataResult
        {
            get; set;
        }

        private ServiceProxy.DataServiceRef.DataResult _dataResult;
        public ServiceProxy.DataServiceRef.DataResult DataResult
        {
            get
            {
                return _dataResult;
            }
            set
            {
                _dataResult = value;
            }
        }

        DispatcherTimer _timer;
        #endregion

        private PartContext _context;

        /// <summary>
        /// 是否是第一次绑定数据
        /// </summary>
        public bool IsFirstDataBind
        {
            get;
            private set;
        }

        #region XEvents
        /// <summary>
        /// DataBind脚本事件
        /// </summary>
        public static XEvent XEventOnDataBind = XEventManager.Register(typeof(DataPart),
            "OnDataBind",
            new XEventArgument("sender", typeof(Script.PartScriptObject)),
            new XEventArgument("data", typeof(Script.DataResultScriptObject)));
        #endregion

        public DataPart()
        {
            XColorPlate = new ColorPlate();
            AddColors();

            XDataAnimationDuration = 2;
            IsFirstDataBind = true;
        }

        protected override void OnInit(PartContext context)
        {
            //BindData(context);
            base.OnInit(context);
        }

        protected override void OnActive(PartContext context)
        {
            // 激活之后将第一次绑定数据的标识置为true
            IsFirstDataBind = true;

            _context = context;

            if (XIsAutoRefresh)
            {
                //Common.Logger.DebugToTag("UI", "part:{0} start timer interval:{1}", this.Name, XAutoRefreshInterval);
                if (_timer == null)
                {
                    _timer = new DispatcherTimer();
                    _timer.Tick += _timer_Tick;
                    _timer.Interval = TimeSpan.FromSeconds(XAutoRefreshInterval);
                    _timer.Start();
                    Logger.DebugToTag(Library.LogDispatcherTimerTAG, string.Format("组件：{0}的自动刷新定时器构造并启动", this.Name));
                }
                else
                {
                    _timer.Start();
                    Logger.DebugToTag(Library.LogDispatcherTimerTAG, string.Format("组件：{0}的自动刷新定时器已经被构造，所以直接启动", this.Name));
                }
            }
            else
            {
                if (_timer != null)
                {
                    _timer.Tick -= _timer_Tick;
                    _timer.Stop();
                    _timer = null;
                }
            }

            if (XIsAutoRefresh)
            {
                BindData(context, false);
            }
            else
            {
                if (PartContext.DataCacheMode == Coolzon.Metadata.DataCacheMode.All)
                {
                    BindData(context, true);
                }
                else
                {
                    BindData(context, false);
                }
            }
            base.OnActive(context);
        }

        protected override void OnDeactive(PartContext context)
        {
            //设计器不清除数据
            if(this._dataResult != null && !string.Equals(System.Configuration.ConfigurationManager.AppSettings["SysName"], "Designer"))
            {
                // 清空数据
                this._dataResult = null;
            }

            if (_timer != null)
            {
                Logger.DebugToTag(Library.LogDispatcherTimerTAG, string.Format("组件：{0}的自动刷新定时器停止并删除", this.Name));
                _timer.Tick -= _timer_Tick;
                _timer.Stop();
                _timer = null;
            }
            base.OnDeactive(context);
        }

        protected override void OnDestory()
        {
            if (_timer != null)
            {
                Logger.DebugToTag(Library.LogDispatcherTimerTAG, string.Format("组件：{0}的自动刷新定时器停止并删除", this.Name));
                _timer.Stop();
                _timer = null;
            }
            base.OnDestory();
        }

        /// <summary>
        /// 刷新数据
        /// </summary>
        protected override void OnRefresh()
        {
            if (_dataResult != null)
            {
                if (IsActived)
                {
                    DataBinding(_dataResult);
                    IsFirstDataBind = false;
                }
            }
            else
            {
                BindData(this.PartContext, false);
            }
        }

        void _timer_Tick(object sender, EventArgs e)
        {
            //Logger.DebugToTag("UI", "控件{0}开始自动刷新数据", this.Name);
            _dataResult = null;
            BindData(_context, false);
        }

        /// <summary>
        /// 绑定数据
        /// </summary>
        /// <param name="context"></param>
        /// <param name="isCacheEnable">是否支持缓存</param>
        public void BindData(PartContext context, bool isCacheEnable)
        {
            if (_dataResult != null)
            {
                if (IsActived)
                {
                    DataBinding(_dataResult);
                    IsFirstDataBind = false;
                }
            }
            else
            {
                if (_isLoadingData)
                {
                    long timeoutTime = DateTime.Now.Ticks - _beginDataLoadTicks;
                    if (timeoutTime > TimeSpan.FromSeconds(30).Ticks)
                    {
                        //Logger.InfoToTag("UI", "控件{0}正在加载数据，上次数据加载超时", this.Name);
                        _isLoadingData = false;
                    }
                    else
                    {
                        //Logger.InfoToTag("UI", "控件{0}正在加载数据，本次不执行加载数据操作", this.Name);
                        return;
                    }
                }
                else if (XDataSource != null)
                {
                    _isLoadingData = true;
                    _beginDataLoadTicks = DateTime.Now.Ticks;

                    List<ServiceProxy.DataServiceRef.DataParameter> parameters = new List<ServiceProxy.DataServiceRef.DataParameter>();

                    // 如果是静态数据源，没有dataset和parameter的设置
                    if(XDataSource.DataSet!=null  && XDataSource.DataSet.Parameters!= null)
                    {
                        for (int index = 0; index < XDataSource.DataSet.Parameters.Count; index++)
                        {
                            UI.DataParameter dataParameter = XDataSource.DataSet.Parameters[index];
                            ServiceProxy.DataServiceRef.DataParameter parameter = new ServiceProxy.DataServiceRef.DataParameter();
                            parameter.Name = dataParameter.Name;
                            parameter.Type = dataParameter.Type;
                            parameter.ValueString = ParseValueString(dataParameter.ValueString);
                            parameters.Add(parameter);
                        }
                    }

                    DataLoadTaskManager.Run(new DataLoadTask(this,
                        "",
                        XDataSource,
                        XDataSource.DataSet,
                        parameters,
                        isCacheEnable));
                }
            }
        }

        /// <summary>
        /// 数据加载完毕之后，此方法将被调用
        /// </summary>
        /// <param name="result"></param>
        public void OnDataClientGetDataCompleted(ServiceProxy.DataServiceRef.DataResult result)
        {
            _isLoadingData = false;
            OriginalDataResult = result;
            if (result != null)
            {
                this._dataResult = ScreeningDataSeries(result);
            }
            else
            {
                this._dataResult = null;
            }

            if (!this.IsActived)
            {
                return;
            }

            if (this.Dispatcher.HasShutdownFinished == false)
            {
                // 程序没有关闭才执行下面的代码
                this.Dispatcher.BeginInvoke(new Action(OnDataBindingToUI));
            }
        }

        private void OnDataBindingToUI()
        {
            try
            {
                if (_dataResult != null)
                {
                    DataBinding(_dataResult);
                }
            }
            catch (Exception ex)
            {
                Common.Logger.ErrorToTag("UI", "OnDataClientGetDataCompleted 出错!ex:{0}", ex);
            }
        }

        //protected override void OnInitScriptEngine(ScriptEngine engine)
        //{
        //    base.OnInitScriptEngine(engine);
        //}

        private void DataBinding(ServiceProxy.DataServiceRef.DataResult dataResult)
        {
            OnDataBinding(dataResult);
            IsFirstDataBind = false;
            ValidateDisplayCondition();

            // 调用脚本
            if (HasScriptEvent(DataPart.XEventOnDataBind.Name))
            {
                this.InvokeScriptEvent(PartContext.ScriptEngine, DataPart.XEventOnDataBind.Name , this.GetScriptObj(), new Script.DataResultScriptObject(dataResult));
            }
        }

        #region abstract methods
        protected abstract void OnDataBinding(ServiceProxy.DataServiceRef.DataResult dataResult);
        #endregion

        /// <summary>
        /// 触发事件
        /// </summary>
        /// <param name="eventType"></param>
        /// <param name="dataItem">触发事件的项目所在的数据项</param>
        protected void RaiseEvent(DataEventType eventType, ServiceProxy.DataServiceRef.DataItem dataItem)
        {
            return;
            /*
            if (this.EventList != null)
            {
                // 扫描组件的所有事件配置
                ScriptEngine script = ScriptEngine.Instance;
                script.AddCode("var args={data:{id:'" + dataItem.Id + "', name:'" + dataItem.Name + "', value:'" + dataItem.Value + "'}};");
                for (int index = 0; index < this.EventList.Count; index++)
                {
                    Metadata.Event @event = this.EventList[index];
                    // 检查事件类型
                    if (@event.Source.ToUpper() == GetDataEventTypeString(eventType))
                    {
                        // 检查事件条件
                        if (string.IsNullOrEmpty(@event.Condition)
                            || (bool)script.RunExpression(@event.Condition))
                        {
                            // 往事件总线中发送数据交互事件
                            ActionUrl url = new ActionUrl(@event.Action);
                            EventContext context = new EventContext();
                            context.ActionType = url.ActionType;
                            context.TargetFrameName = url.TargetFrame;
                            context.TargetSceneName = url.TargetScene;

                            this.InjectionParameters(context, dataItem, url);

                            // 向事件总线发送组件事件响应事件
                            Common.EventBus.Instance.Publish(context);
                        }
                    }
                }
            }
             * */
        }

        /// <summary>
        /// 注入参数的值,最终将值注入到context中，具体有什么值根据url中的parameterstring来定义
        /// </summary>
        /// <param name="context"></param>
        /// <param name="url"></param>
        protected void InjectionParameters(EventContext context, ServiceProxy.DataServiceRef.DataItem dataItem, ActionUrl url)
        {
            // 更细参数的值
            foreach (string key in url.ParameterString.Keys)
            {
                if (context.Arguments.ContainsKey(key))
                {
                    continue;
                }
                string pValue = url.ParameterString[key];
                if (pValue == "args.data.id")
                {
                    context.Arguments.Add(key, dataItem.Id);
                }
                else if (pValue == "args.data.name")
                {
                    context.Arguments.Add(key, dataItem.Name);
                }
                else if (pValue == "args.data.value")
                {
                    context.Arguments.Add(key, dataItem.Value);
                }
            }

            base.InjectionParameters(context, url);
        }

        private string GetDataEventTypeString(DataEventType eventType)
        {
            if (eventType == DataEventType.Click)
            {
                return "ITEMCLICK";
            }
            return "UNKNOWN";
        }

        /// <summary>
        /// 过滤数据串
        /// </summary>
        /// <param name="originalData"></param>
        /// <returns></returns>
        private ServiceProxy.DataServiceRef.DataResult ScreeningDataSeries(ServiceProxy.DataServiceRef.DataResult originalData)
        {
            if (originalData == null)
            {
                return null;
            }
            else if (XDataSeriesFilter == null || XDataSeriesFilter.Count == 0)
            {
                if (XDataItemFilter != null && XDataItemFilter.Count > 0)
                {
                    List<ServiceProxy.DataServiceRef.DataSeries> newSeriesList = new List<ServiceProxy.DataServiceRef.DataSeries>();
                    for (int iSeries = 0; iSeries < originalData.DataSeries.Length; iSeries++)
                    {
                        ServiceProxy.DataServiceRef.DataSeries originalSeries = originalData.DataSeries[iSeries];

                        ServiceProxy.DataServiceRef.DataSeries newSeries = new ServiceProxy.DataServiceRef.DataSeries();
                        newSeries.Id = originalSeries.Id;
                        newSeries.Name = originalSeries.Name;

                        List<ServiceProxy.DataServiceRef.DataItem> itemList = new List<ServiceProxy.DataServiceRef.DataItem>();
                        foreach (var itemId in XDataItemFilter)
                        {
                            for (int iItem = 0; iItem < originalSeries.DataItems.Length; iItem++)
                            {
                                ServiceProxy.DataServiceRef.DataItem item = originalSeries.DataItems[iItem];
                                if (item.Id == itemId)
                                {
                                    itemList.Add(item);
                                }
                            }
                        }
                        newSeries.DataItems = itemList.ToArray();

                        newSeriesList.Add(newSeries);
                    }

                    ServiceProxy.DataServiceRef.DataResult result = new ServiceProxy.DataServiceRef.DataResult();
                    result.Name = originalData.Name;
                    result.DataSeries = newSeriesList.ToArray();
                    return result;
                }
                else
                {
                    return originalData;
                }
            }
            else
            {

                if (XDataItemFilter != null && XDataItemFilter.Count > 0)
                {
                    List<ServiceProxy.DataServiceRef.DataSeries> newSeriesList = new List<ServiceProxy.DataServiceRef.DataSeries>();
                    foreach (var seriesId in XDataSeriesFilter)
                    {
                        for (int iSeries = 0; iSeries < originalData.DataSeries.Length; iSeries++)
                        {
                            ServiceProxy.DataServiceRef.DataSeries originalSeries = originalData.DataSeries[iSeries];

                            if (originalSeries.Id == seriesId)
                            {
                                ServiceProxy.DataServiceRef.DataSeries newSeries = new ServiceProxy.DataServiceRef.DataSeries();
                                newSeries.Id = originalSeries.Id;
                                newSeries.Name = originalSeries.Name;
                                List<ServiceProxy.DataServiceRef.DataItem> newItemList = new List<ServiceProxy.DataServiceRef.DataItem>();
                                foreach (var itemId in XDataItemFilter)
                                {
                                    for (int iItem = 0; iItem < originalSeries.DataItems.Length; iItem++)
                                    {
                                        ServiceProxy.DataServiceRef.DataItem item = originalSeries.DataItems[iItem];
                                        if (item.Id == itemId)
                                        {
                                            newItemList.Add(item);
                                        }
                                    }
                                }
                                newSeries.DataItems = newItemList.ToArray();

                                newSeriesList.Add(newSeries);
                            }
                        }
                    }

                    ServiceProxy.DataServiceRef.DataResult result = new ServiceProxy.DataServiceRef.DataResult();
                    result.Name = originalData.Name;
                    result.DataSeries = newSeriesList.ToArray();
                    return result;
                }
                else
                {
                    List<ServiceProxy.DataServiceRef.DataSeries> seriesList = new List<ServiceProxy.DataServiceRef.DataSeries>();
                    foreach (var seriesId in XDataSeriesFilter)
                    {
                        for (int iSeries = 0; iSeries < originalData.DataSeries.Length; iSeries++)
                        {
                            if (originalData.DataSeries[iSeries].Id == seriesId)
                            {
                                List<ServiceProxy.DataServiceRef.DataItem> itemList = new List<ServiceProxy.DataServiceRef.DataItem>();

                                seriesList.Add(originalData.DataSeries[iSeries]);
                            }
                        }
                    }

                    ServiceProxy.DataServiceRef.DataResult result = new ServiceProxy.DataServiceRef.DataResult();
                    result.Name = originalData.Name;
                    result.DataSeries = seriesList.ToArray();
                    return result;
                }
            }
        }

        #region implement IDataPart

        public void LoadData()
        {
            if (XDataSource != null)
            {
                List<ServiceProxy.DataServiceRef.DataParameter> parameters = new List<ServiceProxy.DataServiceRef.DataParameter>();
                for (int index = 0; index < XDataSource.DataSet.Parameters.Count; index++)
                {
                    UI.DataParameter dataParameter = XDataSource.DataSet.Parameters[index];
                    ServiceProxy.DataServiceRef.DataParameter parameter = new ServiceProxy.DataServiceRef.DataParameter();
                    parameter.Name = dataParameter.Name;
                    parameter.Type = dataParameter.Type;
                    parameter.ValueString = ParseValueString(dataParameter.ValueString);
                    parameters.Add(parameter);
                }
                // 预加载模式，同步读取
                DataLoadTaskManager.Run(new DataLoadTask(this,
                    "",
                    XDataSource,
                    XDataSource.DataSet,
                    parameters));
            }
        }

        #endregion


        /// <summary>
        /// 根据颜色板应用颜色值
        /// </summary>
        /// <param name="chart"></param>
        /// <param name="colorPlate"></param>
        protected virtual void ApplyChartColorPlate(Chart chart, ColorPlate colorPlate)
        {
            if (this.XColorPlate == null)
            {
                return;
            }
            if (chart.Series != null && chart.Series.Count > 0)
            {
                for (int i = 0; i < chart.Series.Count; i++)
                {
                    chart.Series[i].Color = this.XColorPlate.GetColor(i);
                }
            }
        }


        /// <summary>
        /// 添加颜色
        /// </summary>
        /// <param name="color"></param>
        public void AddColor(string colorCode)
        {
            BrushConverter brushConverter = new BrushConverter();
            Brush brush = (SolidColorBrush)brushConverter.ConvertFromString(colorCode);
            this.XColorPlate.AddColor(brush);
        }

        private void AddColors()
        {
            this.AddColor("#7FFF6F06");
            this.AddColor("#7FA4D838");
            this.AddColor("#7FFF0000");
            this.AddColor("#7F00FF00");
            this.AddColor("#7F0000FF");
            this.AddColor("#7FFFFF00");
            this.AddColor("#7FFF00FF");
            this.AddColor("#7F00FFFF");
            this.AddColor("#7F8DB143");
            this.AddColor("#7F871F78");
            this.AddColor("#7FCD7F32");
        }
    }
}
